import paper from 'paper'

const local = {
  from: null,
  to: null,
  rect: null,
  selectedRect: null,
  segment: null,
  resizeRect: null,
  assistLine: null,
}

const moveHitOptions = {
  segments: true,
  // stroke: true,
  tolerance: 3,
}

const clickHitOptions = {
  match: (hitResult) => {
    if (hitResult && hitResult.type === 'pixel') return false
    if (
      hitResult &&
      hitResult.item &&
      (hitResult.item.markType === 'temp_rect' || (hitResult.item.markType === 'rect' && hitResult.item.rectPoint1))
    ) {
      return true
    }
    return false
  },
  segments: true,
  stroke: true,
  bounds: true,
  center: true,
  tolerance: 3,
}

const rectPointNormalSize = 4
const rectPointExpandSize = 16

const onMouseMove = (event) => {
  document.querySelector('body').style.cursor = 'auto'
  if (local.assistLine) {
    local.assistLine.horizontal.remove()
    local.assistLine.vertical.remove()
  }
  let horizontal = new paper.Path()
  horizontal.add(new paper.Point(0, event.point.y))
  horizontal.add(new paper.Point(paper.project.view.viewSize.width, event.point.y))
  horizontal.markType = 'assistLine'
  horizontal.strokeCap = 'round'
  horizontal.strokeColor = 'Cyan'
  horizontal.selectedColor = 'Cyan'
  horizontal.strokeScaling = false
  horizontal.dashArray = [12, 6]
  let vertical = new paper.Path()
  vertical.add(new paper.Point(event.point.x, 0))
  vertical.add(new paper.Point(event.point.x, paper.project.view.viewSize.height))
  vertical.markType = 'assistLine'
  vertical.strokeCap = 'round'
  vertical.strokeColor = 'Cyan'
  vertical.selectedColor = 'Cyan'
  vertical.strokeScaling = false
  vertical.dashArray = [12, 6]
  local.assistLine = {
    horizontal,
    vertical,
  }

  if (local.from) {
    local.to = event.point
    if (local.rect) removeRect(local.rect)
    local.rect = drawRect(local.from, local.to, 'yellow')
    return
  }

  const hitResult = paper.project.hitTest(event.point, moveHitOptions)
  paper.project.activeLayer.children.forEach((child) => {
    if (child.markType === 'rectPoint' || child.markType === 'rectPoint1') {
      child.strokeWidth = rectPointNormalSize
    }
  })

  if (
    hitResult &&
    hitResult.item &&
    (hitResult.item.markType === 'rectPoint' || hitResult.item.markType === 'rectPoint1')
  ) {
    hitResult.item.strokeWidth = rectPointExpandSize
    if (hitResult.item.markType === 'rectPoint1') {
      document.querySelector('body').style.cursor = 'move'
      local.rectPoint1 = hitResult.item
      local.segment = null
      local.selectedRect = null
    } else {
      local.rectPoint1 = null
      if (hitResult.item.pointIndex && hitResult.item.pointIndex % 2 == 0)
        document.querySelector('body').style.cursor = 'nw-resize'
      else document.querySelector('body').style.cursor = 'ne-resize'
      local.segment = {
        point: {
          x: hitResult.item.segments[0].point.x,
          y: hitResult.item.segments[0].point.y,
        },
      }
      local.resizeRect = hitResult.item.rect
    }

    if (local.assistLine) {
      local.assistLine.horizontal.remove()
      local.assistLine.vertical.remove()
    }
  } else {
    local.segment = null
    local.rectPoint1 = null
  }
}

const onMouseDown = (event) => {
  if (event.event.buttons === 2) {
    if (local.rect) removeRect(local.rect)
    local.from = null
    local.rect = null
    return
  }

  if (local.selectedRect) {
    local.selectedRect.selected = false
    local.selectedRect = null
  }

  if (local.from) {
    drawRectPoint1(local.rect)
    if (tool.newMarkEvent) {
      tool.newMarkEvent(local.rect, function (params) {
        if (params.ret !== 'confirm') {
          removeRect(local.rect)
        }
        local.rect = null
      })
    }
    local.from = null
    return
  }

  if (local.rectPoint1) {
    return
  }

  let hitResults = paper.project.hitTestAll(event.point, clickHitOptions)
  for (let hitResult of hitResults) {
    if (
      hitResult &&
      (hitResult.item.markType === 'temp_rect' || (hitResult.item.markType === 'rect' && hitResult.item.rectPoint1))
    ) {
      if (hitResult.item.bounds.contains(event.point)) {
        local.selectedRect = hitResult.item
        local.selectedRect.selected = true
        break
      }
    }
  }

  if (!local.selectedRect) {
    for (let child of paper.project.activeLayer.children) {
      if (child && (child.markType === 'temp_rect' || (child.markType === 'rect' && child.rectPoint1))) {
        if (child.bounds.contains(event.point)) {
          local.selectedRect = child
          break
        }
      }
    }
  }

  if (!local.from) {
    local.from = event.point
  }
}

const onMouseDrag = (event) => {
  if (event.event.buttons == 2) {
    if (paper.project.activeLayer.rasterLayer) {
      paper.project.activeLayer.rasterLayer.position.x += event.delta.x
      paper.project.activeLayer.rasterLayer.position.y += event.delta.y
      paper.project.activeLayer.position.x += event.delta.x
      paper.project.activeLayer.position.y += event.delta.y
    }
    return
  }

  if (local.assistLine) {
    local.assistLine.horizontal.remove()
    local.assistLine.vertical.remove()
  }
  local.from = null
  if (local.segment) {
    local.resizeRect.segments.forEach((element) => {
      if (element.point.x == local.segment.point.x) {
        element.point.x += event.delta.x
      }
      if (element.point.y == local.segment.point.y) {
        element.point.y += event.delta.y
      }
    })
    local.resizeRect.points.forEach((point) => {
      if (point.position.x == local.segment.point.x) {
        point.position.x += event.delta.x
      }
      if (point.position.y == local.segment.point.y) {
        point.position.y += event.delta.y
      }
    })
    local.segment.point.x += event.delta.x
    local.segment.point.y += event.delta.y
    local.resizeRect.rectPoint1.position.x += event.delta.x
    local.resizeRect.rectPoint1.position.y += event.delta.y
  } else if (local.selectedRect) {
    document.querySelector('body').style.cursor = 'move'
    moveRect(local.selectedRect, event.delta)
  } else if (local.rectPoint1) {
    document.querySelector('body').style.cursor = 'move'
    const rect = local.rectPoint1.rect
    const deltaPoint = new paper.Point(
      local.rectPoint1.position.x + event.delta.x,
      local.rectPoint1.position.y + event.delta.y
    )
    if (rect.contains(deltaPoint)) {
      local.rectPoint1.position.x += event.delta.x
      local.rectPoint1.position.y += event.delta.y
    }
  }
}

const onMouseUp = (event) => {}

const onKeyDown = (event) => {
  if (event.key === 'delete' && local.selectedRect) {
    removeRect(local.selectedRect)
    local.selectedRect = null
  }
}

const onToggleIn = () => {}

const onToggleOut = () => {
  document.querySelector('body').style.cursor = 'auto'
  if (local.assistLine) {
    local.assistLine.horizontal.remove()
    local.assistLine.vertical.remove()
  }
}

function globalToLocal(point) {
  return paper.project.activeLayer.rasterLayer.globalToLocal(point)
}

function drawRect(from, to, color) {
  const rect = new paper.Path.Rectangle(from, to)
  rect.markType = 'temp_rect'
  rect.action = 'addNew'
  rect.toDBObject = function () {
    const maxMinValue = this.getMaxMinValue()
    let point1 = new paper.Point(maxMinValue.xmin, maxMinValue.ymin)
    let point2 = new paper.Point(maxMinValue.xmax, maxMinValue.ymax)
    let point3 = this.rectPoint1.segments[0].point
    point1 = globalToLocal(point1)
    point2 = globalToLocal(point2)
    point3 = globalToLocal(point3)
    const ret = {
      mMarkAnnotationId: null,
      mQaResultId: this.mQaResultId,
      name: this.labelName,
      x: point1.x + ';' + point2.x + ';' + point3.x + ';',
      y: point1.y + ';' + point2.y + ';' + point3.y + ';',
      z: 'rectPoint1',
      a1: this.a1,
      a2: this.a2,
      a3: this.a3,
      a4: this.a4,
      a5: this.a5,
      a6: this.a6,
      a7: this.a7,
      a8: this.a8,
      fileType: '2d',
      fileName: this.fileName,
    }
    return ret
  }
  rect.getMaxMinValue = function () {
    let xmin, xmax, ymin, ymax
    this.points.forEach((point) => {
      point = point.segments[0].point
      if (xmin) {
        xmin = Math.min(xmin, point.x)
      } else {
        xmin = point.x
      }

      if (xmax) {
        xmax = Math.max(xmax, point.x)
      } else {
        xmax = point.x
      }

      if (ymin) {
        ymin = Math.min(ymin, point.y)
      } else {
        ymin = point.y
      }

      if (ymax) {
        ymax = Math.max(ymax, point.y)
      } else {
        ymax = point.y
      }
    })
    return { xmin, xmax, ymin, ymax }
  }

  rect.fileName = paper.project.fileName
  rect.mQaResultId = paper.project.mQaResultId
  rect.strokeColor = color
  rect.selectedColor = color
  rect.strokeScaling = false
  rect.opacity = 1
  rect.points = []
  let index = 1

  for (let element of rect.segments) {
    const point = new paper.Path()
    point.add(element.point)
    point.markType = 'rectPoint'
    point.strokeCap = 'round'
    point.strokeColor = 'red'
    point.selectedColor = 'red'
    point.strokeScaling = false
    point.strokeWidth = rectPointNormalSize
    point.opacity = 1
    point.closed = true
    point.rect = rect
    point.pointIndex = index++
    rect.points.push(point)
  }

  return rect
}

function removeRect(rect) {
  rect.points.forEach((point) => {
    point.remove()
  })
  if (rect.rectPoint1) {
    rect.rectPoint1.remove()
  }
  rect.remove()
}

function moveRect(rect, delta) {
  rect.position.x += delta.x
  rect.position.y += delta.y
  rect.points.forEach((point) => {
    point.position.x += delta.x
    point.position.y += delta.y
  })
  rect.rectPoint1.position.x += delta.x
  rect.rectPoint1.position.y += delta.y
}

function drawRectPoint1(rect) {
  const ret = rect.getMaxMinValue()
  const point = new paper.Path()
  point.add(new paper.Point((ret.xmin + ret.xmax) / 2, ret.ymax))
  point.markType = 'rectPoint1'
  point.strokeCap = 'round'
  point.strokeColor = 'red'
  point.selectedColor = 'red'
  point.strokeScaling = false
  point.strokeWidth = rectPointNormalSize
  point.opacity = 1
  point.closed = true
  point.rect = rect
  rect.rectPoint1 = point
}

export const tool = new paper.Tool()
tool.onMouseDown = onMouseDown
tool.onMouseDrag = onMouseDrag
tool.onMouseUp = onMouseUp
tool.onMouseMove = onMouseMove
tool.onKeyDown = onKeyDown
tool.onToggleIn = onToggleIn
tool.onToggleOut = onToggleOut
tool.name = 'rectPoint1'
